import { v4 as uuidv4 } from 'uuid';
import type { FlowNode, FlowEdge, JDFAttribute } from '@/models/jdf';
import type { ParseResult } from './types';

/**
 * Parses XML content using the browser's built-in DOMParser.
 * 
 * @param content The XML string content.
 * @returns A ParseResult object.
 */
export function parse(content: string): ParseResult {
    try {
        const parser = new DOMParser();
        const xmlDoc = parser.parseFromString(content, 'text/xml');

        // Check for parsing errors
        const parseError = xmlDoc.querySelector('parsererror');
        if (parseError) {
            // Try to extract a more specific message
            const errorText = parseError.textContent || 'Invalid XML document';
            return {
                success: false,
                error: `DOMParser Error: ${errorText.split('\n')[0]}`, // Get first line of error
                nodes: [],
                edges: []
            };
        }

        // If no parsererror tag, assume basic syntax is okay
        if (!xmlDoc.documentElement) {
             throw new Error('No document element found after parsing.');
        }

        // Extract flow elements (nodes and edges)
        const { nodes, edges } = extractElementsFromDOM(xmlDoc.documentElement);

        return {
            success: true,
            document: xmlDoc, // Keep the original DOM document if needed elsewhere
            nodes,
            edges
        };
    } catch (err: any) {
        console.error('[DOMParserWrapper] Error:', err);
        return {
            success: false,
            error: err.message || 'An unexpected error occurred during DOM parsing.',
            nodes: [],
            edges: []
        };
    }
}

// --- Helper functions specific to DOM traversal --- 

/**
 * Extracts FlowNode and FlowEdge arrays by traversing the DOM tree.
 * @param rootNode The root element of the XML document.
 * @returns An object containing the extracted nodes and edges.
 */
function extractElementsFromDOM(rootNode: Element): { nodes: FlowNode[]; edges: FlowEdge[] } {
    const nodes: FlowNode[] = [];
    const edges: FlowEdge[] = [];

    // Start recursive processing from the root DOM element
    processDOMNode(rootNode, null, nodes, edges, 0);

    return { nodes, edges };
}

/**
 * Recursively processes a DOM node to create FlowNode and FlowEdge objects.
 * 
 * @param node The current DOM Element.
 * @param parentId The ID of the parent FlowNode (or null for root).
 * @param nodes The array to add created FlowNodes to.
 * @param edges The array to add created FlowEdges to.
 * @param level The current depth in the tree.
 * @returns The generated ID of the created FlowNode.
 */
function processDOMNode(node: Element, parentId: string | null, nodes: FlowNode[], edges: FlowEdge[], level: number): string {
    const nodeId = `node-${uuidv4()}`;

    // Extract attributes from the DOM element
    const attributes: JDFAttribute[] = Array.from(node.attributes).map(attr => ({
        name: attr.name,
        value: attr.value
    }));

    // Extract text content (only if it's the single child)
    let textContent = '';
    if (node.childNodes.length === 1 && node.firstChild?.nodeType === Node.TEXT_NODE) {
        textContent = node.textContent?.trim() || '';
    }

    // Find child DOM elements
    const childElements = Array.from(node.children);
    const hasChildren = childElements.length > 0;

    // Recursively process child elements first to get their IDs
    const childrenIds: string[] = [];
    childElements.forEach(child => {
        const childId = processDOMNode(child, nodeId, nodes, edges, level + 1);
        childrenIds.push(childId);
    });

    // Create the FlowNode for the current DOM element
    const flowNode: FlowNode = {
        id: nodeId,
        type: 'jdfNode', // Assuming a default node type
        position: { x: 0, y: 0 }, // Position will be set by layout later
        data: {
            nodeName: node.nodeName,
            attributes,
            textContent,
            hasChildren,
            level,
            isExpanded: true, // Default to expanded
            childrenIds: childrenIds
        },
        parentId: parentId ?? undefined,
        hidden: false // Default to visible, will be updated by layout/interaction
    };

    nodes.push(flowNode);

    // Create an edge connecting to the parent FlowNode
    if (parentId) {
        const edgeId = `edge-${parentId}-${nodeId}`;
        const edge: FlowEdge = {
            id: edgeId,
            source: parentId,
            target: nodeId,
            type: 'smoothstep', // Default edge type
            hidden: false
        };
        edges.push(edge);
    }

    return nodeId; // Return the new node's ID
} 